use std::{
    net::{IpAddr, SocketAddr},
    sync::Arc,
};

use crate::{
    cache::Metadata,
    handler::{Connection, Handler},
    wal::segment::WalWriter,
    Error, SendMessage, MESSAGE_QUEUE_SIZE,
};
use log::{error, info};
use tokio::{
    net::TcpListener,
    sync::{
        broadcast::{self, Sender},
        Mutex,
    },
};

pub struct Server {
    pub sender: Sender<SendMessage>,
}

impl Server {
    pub fn new() -> Self {
        let (sender, receiver) = broadcast::channel::<SendMessage>(MESSAGE_QUEUE_SIZE);
        WalWriter::new(receiver);
        Server { sender }
    }

    pub async fn start(&mut self, ip: IpAddr, port: u16) -> Result<(), Error> {
        let socket_addr = SocketAddr::new(ip, port);
        let listener = match TcpListener::bind(socket_addr).await {
            Ok(listener) => listener,
            Err(e) => {
                error!("tcp listener bind error. {}", e);
                return Err(Error::CustomError("start tcp listener error".to_owned()));
            }
        };

        info!("server started addr: {}", socket_addr.to_string());

        let metadata = Arc::new(Mutex::new(Metadata::default()));

        loop {
            let (socket, _) = match listener.accept().await {
                Ok((socket, a)) => (socket, a),
                Err(e) => {
                    error!("socket accapt error. {}", e);
                    return Err(Error::CustomError("start tcp listener error".to_owned()));
                }
            };

            let metadata_clone = Arc::clone(&metadata);
            let connection = Connection::new(socket, self.sender.clone());
            tokio::spawn(async move {
                let mut handler = Handler::new(metadata_clone);
                let _ = handler.command(connection).await;
            });
        }

        //Ok(())
    }
}
